#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

// 7.创建一个缓冲区
const int size = 1024;
// 5.用于获取动态信息，获取子进程的pid,以及一个计数器，
std::string getOtherMessage()
{
    static int cnt = 0;                      // 计数器
    std::string msgid = std::to_string(cnt); // stoi是字符串转整数
    cnt++;
    pid_t self_id = getpid(); // #include<unistd.h>,#include<sys/types.h>
    std::string string_pid = std::to_string(self_id);

    std::string message = "msg_id: ";
    message += msgid;
    message += ", my_pid: ";
    message += string_pid;

    return message;
}

// 4.让子进程进行写入
void SubProcessWrite(int wfd)
{
    int pipesize = 0;
    char c = 'A';

    std::string msg = "father, i am your son process!";
    while (true)
    {
        std::cerr << "++++++++++++++++++++++++++++++++++++++++++++"<< std::endl;
        //让子进程一直写入不退出
        std::string info = msg + getOtherMessage();
        //6.子进程发送信息给父进程 --- write()系统调用接口---><unistd.h>
        write(wfd, info.c_str(), info.size());//write("向谁写入：wfd"，"写什么: info.c_str()"，"写入的字符个数: info.size()")
                                    //在这里，写入管道的时候，没有写入\0，没必要
      
        //让子进程将内容往标准错误中打                            
        std::cerr << info << std::endl;
      
      
      
      
      
         // sleep(1);
        // write(wfd, &c, 1);
        // std::cout << "pipesize: " << ++pipesize << ", write charactor is: " << c++ <<  std::endl;
        // if(c == 'G')
        // {
        //     break;
        // }
        // sleep(1);
    }
    std::cout << "child quit ..." << std::endl;
}
// 4.让父进程来进行读取
void FatherProcessRead(int rfd)
{
    char inbuffer[size]; // c99 gnu g99标准是可以使用变量做数组大小
    while (true)
    {
        sleep(2);
        std::cout << "--------------------------------------------------------" << std::endl;
        ssize_t n = read(rfd, inbuffer, sizeof(inbuffer) - 1); // read(“从哪里读取：rfd”, “读取到哪里：inbuffer”, “期望读取多少：不读\0:sizeof(inbuffer)”)
        if (n > 0)
        {
            inbuffer[n] = 0; //=='\0'
            // std::cout << "father get message: " << inbuffer << std::endl;
            //让父进程直接向标准输出中打
            std::cout << inbuffer << std::endl;

        }
        // 如果read的返回值为0， 表示写端直接关闭了，我们读到了文件的结尾。
        else if(n == 0)
        {
            std::cout << "child quit, father get return val: " << n <<", father quit too!"<<std::endl;
            break; 
        }
        else if(n < 0)
        {
            std::cerr<< "read error " << std::endl;
        }
        // sleep(1);
        // break;//让父进程读一次就直接退出
    }
}

int main()
{
    // close(0);
    // 1.创建管道
    int pipefd[2];
    int n = pipe(pipefd); // 输出型参数，rfd，wfd
    if (n != 0)
    {
        std::cerr << "errno" << errno << ":" << "errstring" << strerror(errno);
        return 1;
    }
    // 注意：pipefd[0]->下标为0 -> r(嘴巴 -> 读)，pipefd[1]->下标为1 -> w（笔->写）
    std::cout << "pipefd[0]: " << pipefd[0] << ", pipefd[1]: " << pipefd[1] << std::endl;
    sleep(1);
    // 2.创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        std::cout << "子进程关闭不需要的fd了， 准备发消息了" << std::endl;

        sleep(1);
        // 子进程
        // 3.关闭不需要的描述符
        close(pipefd[0]);

        // if (fork() > 0)
        // {
        //     exit(0); // 往后通信的就是孙子进程
        // }
        // 4.让子进程进行写入
        SubProcessWrite(pipefd[1]);

        close(pipefd[1]);
        exit(0);
    }
    std::cout << "父进程关闭不需要的fd了， 准备接收消息了" << std::endl;
    sleep(1);
    // 父进程
    // 3.关闭不需要的描述符
    close(pipefd[1]);
    // 4.让父进程来进行读取
    FatherProcessRead(pipefd[0]);
    std::cout << "5s后，father close rfd!!" << std::endl;
    sleep(5);
    close(pipefd[0]);

    int status = 0;//获取子进程的退出信息

    pid_t rid = waitpid(id, &status, 0); // #include<sys/wait.h>
    if (rid > 0)
    {
        std::cout << "wait child process success!, exit sig: " << (status&0x7f) <<std::endl;
        std::cout << "wait child process success!, exit code(ignore): " << (status>>8&0xff) <<std::endl;
    }

    return 0;
}

// 打开终端：ctrl + shift + `